package com.itheima.Wuziqi.entity;

import com.itheima.Wuziqi.ui.Board;
import com.itheima.Wuziqi.service.GameRule;

import java.awt.Point;
import java.util.Random;

/**
 * 改进的AI玩家实现
 */
public class AIPlayer implements Player {
    private int type;
    private String name;
    private int difficulty; // 1-简单, 2-中等, 3-困难
    
    // 评分权重
    private static final int WIN_SCORE = 1000000;
    private static final int BLOCKED_FOUR_SCORE = 100000;
    private static final int OPEN_FOUR_SCORE = 50000;
    private static final int BLOCKED_THREE_SCORE = 10000;
    private static final int OPEN_THREE_SCORE = 5000;
    private static final int BLOCKED_TWO_SCORE = 1000;
    private static final int OPEN_TWO_SCORE = 500;
    
    public AIPlayer(int type, int difficulty) {
        this.type = type;
        this.difficulty = difficulty;
        this.name = "AI (难度: " + getDifficultyName() + ")";
    }
    
    private String getDifficultyName() {
        switch(difficulty) {
            case 1: return "简单";
            case 2: return "中等";
            case 3: return "困难";
            default: return "未知";
        }
    }
    
    @Override
    public int getType() {
        return type;
    }
    
    @Override
    public Point makeMove(Board board, GameRule rule) {
        int depth = 2 + difficulty; // 根据难度调整搜索深度
        return findBestMove(board, rule, depth);
    }
    
    // 寻找最佳落子位置
    private Point findBestMove(Board board, GameRule rule, int depth) {
        int size = board.getSize();
        int[][] currentBoard = board.getBoardState();
        int bestScore = Integer.MIN_VALUE;
        Point bestMove = null;
        Random random = new Random();
        
        // 先检查是否有能直接获胜的位置
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (currentBoard[i][j] == 0) {
                    // 模拟落子
                    currentBoard[i][j] = type;
                    boolean isWin = rule.checkWin(currentBoard, i, j, type);
                    currentBoard[i][j] = 0; // 撤销落子
                    
                    if (isWin) {
                        return new Point(j, i); // 直接返回获胜位置
                    }
                }
            }
        }
        
        // 检查是否需要阻止对手获胜
        int opponent = (type == Player.BLACK) ? Player.WHITE : Player.BLACK;
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (currentBoard[i][j] == 0) {
                    // 模拟对手落子
                    currentBoard[i][j] = opponent;
                    boolean isWin = rule.checkWin(currentBoard, i, j, opponent);
                    currentBoard[i][j] = 0; // 撤销落子
                    
                    if (isWin) {
                        return new Point(j, i); // 阻止对手获胜
                    }
                }
            }
        }
        
        // 使用极小极大算法带Alpha-Beta剪枝寻找最佳位置
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (currentBoard[i][j] == 0) {
                    // 只评估有棋子周围的位置，提高效率
                    if (hasAdjacentPieces(currentBoard, i, j, 2) || i == size/2 && j == size/2) {
                        currentBoard[i][j] = type;
                        int score = minimax(currentBoard, rule, depth - 1, Integer.MIN_VALUE, Integer.MAX_VALUE, false);
                        currentBoard[i][j] = 0; // 撤销落子
                        
                        // 增加一定随机性，使AI行为更难预测
                        if (score > bestScore || (score == bestScore && random.nextBoolean())) {
                            bestScore = score;
                            bestMove = new Point(j, i);
                        }
                    }
                }
            }
        }
        
        // 如果没有找到好位置，返回中心或随机位置
        if (bestMove == null) {
            if (currentBoard[size/2][size/2] == 0) {
                return new Point(size/2, size/2);
            } else {
                // 随机选择一个位置
                int i, j;
                do {
                    i = random.nextInt(size);
                    j = random.nextInt(size);
                } while (currentBoard[i][j] != 0);
                return new Point(j, i);
            }
        }
        
        return bestMove;
    }
    
    // 极小极大算法带Alpha-Beta剪枝
    private int minimax(int[][] board, GameRule rule, int depth, int alpha, int beta, boolean isMaximizingPlayer) {
        int size = board.length;
        int currentPlayer = isMaximizingPlayer ? type : (type == Player.BLACK ? Player.WHITE : Player.BLACK);
        
        // 检查游戏是否结束或达到搜索深度
        if (depth == 0) {
            return evaluateBoard(board);
        }
        
        // 检查当前玩家是否获胜
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (board[i][j] == currentPlayer) {
                    if (rule.checkWin(board, i, j, currentPlayer)) {
                        return isMaximizingPlayer ? WIN_SCORE : -WIN_SCORE;
                    }
                }
            }
        }
        
        // 检查平局
        if (rule.checkDraw(board)) {
            return 0;
        }
        
        if (isMaximizingPlayer) {
            int maxScore = Integer.MIN_VALUE;
            for (int i = 0; i < size; i++) {
                for (int j = 0; j < size; j++) {
                    if (board[i][j] == 0 && hasAdjacentPieces(board, i, j, 2)) {
                        board[i][j] = currentPlayer;
                        int score = minimax(board, rule, depth - 1, alpha, beta, false);
                        board[i][j] = 0;
                        
                        maxScore = Math.max(score, maxScore);
                        alpha = Math.max(alpha, score);
                        
                        if (beta <= alpha) {
                            break; // Beta剪枝
                        }
                    }
                }
                if (beta <= alpha) {
                    break; // Beta剪枝
                }
            }
            return maxScore;
        } else {
            int minScore = Integer.MAX_VALUE;
            for (int i = 0; i < size; i++) {
                for (int j = 0; j < size; j++) {
                    if (board[i][j] == 0 && hasAdjacentPieces(board, i, j, 2)) {
                        board[i][j] = currentPlayer;
                        int score = minimax(board, rule, depth - 1, alpha, beta, true);
                        board[i][j] = 0;
                        
                        minScore = Math.min(score, minScore);
                        beta = Math.min(beta, score);
                        
                        if (beta <= alpha) {
                            break; // Alpha剪枝
                        }
                    }
                }
                if (beta <= alpha) {
                    break; // Alpha剪枝
                }
            }
            return minScore;
        }
    }
    
    // 评估棋盘状态
    private int evaluateBoard(int[][] board) {
        int score = 0;
        int size = board.length;
        int opponent = (type == Player.BLACK) ? Player.WHITE : Player.BLACK;
        
        // 评估棋盘上每个位置的模式
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (board[i][j] == type) {
                    score += evaluatePosition(board, i, j, type);
                } else if (board[i][j] == opponent) {
                    score -= evaluatePosition(board, i, j, opponent);
                }
            }
        }
        
        return score;
    }
    
    // 评估特定位置的价值
    private int evaluatePosition(int[][] board, int row, int col, int player) {
        int score = 0;
        int size = board.length;
        int[][] directions = {{0, 1}, {1, 0}, {1, 1}, {1, -1}};
        
        for (int[] dir : directions) {
            // 检查当前方向上的棋子模式
            int[] pattern = getPattern(board, row, col, dir, player, size);
            score += evaluatePattern(pattern);
        }
        
        return score;
    }
    
    // 获取特定方向上的棋子模式
    private int[] getPattern(int[][] board, int row, int col, int[] dir, int player, int size) {
        int opponent = (player == Player.BLACK) ? Player.WHITE : Player.BLACK;
        int[] pattern = new int[9]; // 存储当前位置及周围各4个位置的模式
        pattern[4] = 1; // 当前位置是自己的棋子
        
        // 向一个方向检查
        for (int i = 1; i <= 4; i++) {
            int r = row + i * dir[0];
            int c = col + i * dir[1];
            
            if (r < 0 || r >= size || c < 0 || c >= size) {
                pattern[4 + i] = -1; // 边界
            } else if (board[r][c] == player) {
                pattern[4 + i] = 1; // 自己的棋子
            } else if (board[r][c] == opponent) {
                pattern[4 + i] = 2; // 对手的棋子
            } else {
                pattern[4 + i] = 0; // 空位
            }
        }
        
        // 向相反方向检查
        for (int i = 1; i <= 4; i++) {
            int r = row - i * dir[0];
            int c = col - i * dir[1];
            
            if (r < 0 || r >= size || c < 0 || c >= size) {
                pattern[4 - i] = -1; // 边界
            } else if (board[r][c] == player) {
                pattern[4 - i] = 1; // 自己的棋子
            } else if (board[r][c] == opponent) {
                pattern[4 - i] = 2; // 对手的棋子
            } else {
                pattern[4 - i] = 0; // 空位
            }
        }
        
        return pattern;
    }
    
    // 评估棋子模式的价值
    private int evaluatePattern(int[] pattern) {
        // 检查是否有五连珠
        if (hasSequence(pattern, 1, 5)) {
            return WIN_SCORE;
        }
        
        // 检查冲四（活四被挡住一端）
        if (hasBlockedFour(pattern)) {
            return BLOCKED_FOUR_SCORE;
        }
        
        // 检查活四（两端都有空位的四连珠）
        if (hasOpenFour(pattern)) {
            return OPEN_FOUR_SCORE;
        }
        
        // 检查冲三（活三被挡住一端）
        if (hasBlockedThree(pattern)) {
            return BLOCKED_THREE_SCORE;
        }
        
        // 检查活三（两端都有空位的三连珠）
        if (hasOpenThree(pattern)) {
            return OPEN_THREE_SCORE;
        }
        
        // 检查冲二（活二被挡住一端）
        if (hasBlockedTwo(pattern)) {
            return BLOCKED_TWO_SCORE;
        }
        
        // 检查活二（两端都有空位的二连珠）
        if (hasOpenTwo(pattern)) {
            return OPEN_TWO_SCORE;
        }
        
        return 0;
    }
    
    // 检查是否有连续n个特定值
    private boolean hasSequence(int[] pattern, int value, int n) {
        int count = 0;
        for (int p : pattern) {
            if (p == value) {
                count++;
                if (count >= n) {
                    return true;
                }
            } else {
                count = 0;
            }
        }
        return false;
    }
    
    // 检查是否有冲四模式
    private boolean hasBlockedFour(int[] pattern) {
        // 模式如：11110、01111、211110、011112等（2表示对手棋子）
        String str = arrayToString(pattern);
        return str.contains("11110") || str.contains("01111") || 
               str.contains("211110") || str.contains("011112") ||
               str.contains("11101") || str.contains("10111") ||
               str.contains("11011");
    }
    
    // 检查是否有活四模式
    private boolean hasOpenFour(int[] pattern) {
        // 模式如：011110
        String str = arrayToString(pattern);
        return str.contains("011110") || 
               str.contains("0110110") ||  // 特殊情况的活四
               str.contains("0101110") ||
               str.contains("0111010");
    }
    
    // 检查是否有冲三模式
    private boolean hasBlockedThree(int[] pattern) {
        String str = arrayToString(pattern);
        return str.contains("11100") || str.contains("00111") ||
               str.contains("01110") || str.contains("211100") ||
               str.contains("001112") || str.contains("11010") ||
               str.contains("01011") || str.contains("10110") ||
               str.contains("01101");
    }
    
    // 检查是否有活三模式
    private boolean hasOpenThree(int[] pattern) {
        String str = arrayToString(pattern);
        return str.contains("011100") || str.contains("001110") ||
               str.contains("011010") || str.contains("010110") ||
               str.contains("0010110") || str.contains("01100110");
    }
    
    // 检查是否有冲二模式
    private boolean hasBlockedTwo(int[] pattern) {
        String str = arrayToString(pattern);
        return str.contains("11000") || str.contains("00011") ||
               str.contains("01100") || str.contains("00110") ||
               str.contains("01010") || str.contains("01001") ||
               str.contains("10010");
    }
    
    // 检查是否有活二模式
    private boolean hasOpenTwo(int[] pattern) {
        String str = arrayToString(pattern);
        return str.contains("011000") || str.contains("000110") ||
               str.contains("001100") || str.contains("010100") ||
               str.contains("001010") || str.contains("010010");
    }
    
    // 将数组转换为字符串以便模式匹配
    private String arrayToString(int[] array) {
        StringBuilder sb = new StringBuilder();
        for (int num : array) {
            sb.append(num);
        }
        return sb.toString();
    }
    
    // 检查指定位置周围是否有棋子（提高搜索效率）
    private boolean hasAdjacentPieces(int[][] board, int row, int col, int distance) {
        int size = board.length;
        
        for (int i = Math.max(0, row - distance); i <= Math.min(size - 1, row + distance); i++) {
            for (int j = Math.max(0, col - distance); j <= Math.min(size - 1, col + distance); j++) {
                if (board[i][j] != 0) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    @Override
    public String getName() {
        return name;
    }
    
    public int getDifficulty() {
        return difficulty;
    }
    
    public void setDifficulty(int difficulty) {
        this.difficulty = difficulty;
        this.name = "AI (难度: " + getDifficultyName() + ")";
    }
}
    